﻿// <copyright file="AdminController.cs">
//  Copyright (c) 2008 Eric Patey
//
//  Permission is hereby granted, free of charge, to any person
//  obtaining a copy of this software and associated documentation
//  files (the "Software"), to deal in the Software without
//  restriction, including without limitation the rights to use,
//  copy, modify, merge, publish, distribute, sublicense, and/or sell
//  copies of the Software, and to permit persons to whom the
//  Software is furnished to do so, subject to the following
//  conditions:
//
//  The above copyright notice and this permission notice shall be
//  included in all copies or substantial portions of the Software.
//
//  THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
//  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
//  OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
//  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
//  HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
//  WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
//  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
//  OTHER DEALINGS IN THE SOFTWARE.
// </copyright>

namespace WaringAuction.Controllers
{
    using System.Linq;
    using System.Xml.Linq;
    using System.Net;
    using System.Web;
    using System.Web.Mvc;
    using EricUtilities.Azure;
    using WaringAuction.Models;
    using System.Xml;
    using System;
    using System.Text;
    using System.Data.Services.Client;
    using System.Collections.Generic;

    [HandleError]
    public class AdminController : ControllerBase
    {
        public ActionResult Index()
        {
            ViewData["Title"] = "Index";
            return View();
        }

        public ActionResult CreateItem()
        {
            AuctionDataServiceContext ctx = new AuctionDataServiceContext(this.TableAccountInfo);

            ViewData["Title"] = "Create Item";
            ViewData["Categories"] = ctx.Categories;
            return View();
        }

        [AcceptVerbs(HttpVerbs.Post)]
        public ActionResult CreateItem(
            string name,
            string category,
            string description,
            string donor,
            int? estimatedValue)
        {
            if (string.IsNullOrEmpty(name))
            {
                this.ViewData.ModelState.AddModelError("Name", "Please enter an item name");
            }

            if (string.IsNullOrEmpty(category))
            {
                this.ViewData.ModelState.AddModelError("Category", "Please select a category");
            }

            if (string.IsNullOrEmpty(description))
            {
                this.ViewData.ModelState.AddModelError("Description", "Please enter an item description");
            }

            if (string.IsNullOrEmpty(donor))
            {
                this.ViewData.ModelState.AddModelError("Donor", "Please enter an item donor");
            }

            if (!this.ViewData.ModelState.IsValid)
            {
                return this.CreateItem();
            }

            string fullSizeImage;
            string thumbnailImage;
            CreateImages(out fullSizeImage, out thumbnailImage);

            AuctionItem item = new AuctionItem()
            {
                Number = SequenceNumber.GetNextSequenceNumber(this.TableAccountInfo, "ItemNumber"),
                Name = name,
                Description = description,
                Donor = donor,
                EstimatedValue = estimatedValue ?? 0,
                FullSizeImage = fullSizeImage,
                Thumbnail = thumbnailImage
            };
            AuctionDataServiceContext ctx = new AuctionDataServiceContext(this.TableAccountInfo);
            ctx.AddObject(AuctionDataServiceContext.AuctionItemsTableName, item);
            ctx.SaveChangesWithRetries();

            return this.CreateItem();
        }

        private bool CreateImages(out string fullSizeImage, out string thumbnailImage)
        {
            if (this.Request.Files.Count == 1 && this.Request.Files[0].ContentLength != 0)
            {
                HttpPostedFileBase file = this.Request.Files[0];
                Utilities.CreateFileBlobAndThumbnail(
                    file,
                    this.BlobContainer,
                    350,
                    350,
                    true,
                    out fullSizeImage,
                    out thumbnailImage);
                return true;
            }
            else
            {
                fullSizeImage = null;
                thumbnailImage = null;
                return false;
            }

        }

        public ActionResult EditItem(int id)
        {
            ViewData["Title"] = "EditItem";
            this.ViewData["blobContainerUri"] = this.BlobContainer.ContainerUri.ToString() + "/";

            AuctionDataServiceContext ctx = new AuctionDataServiceContext(this.TableAccountInfo);
            AuctionItem item = ctx.AuctionItems.Where<AuctionItem>(i => i.PartitionKey == id.ToString()).SingleOrDefault<AuctionItem>();
            if (item == null)
            {
                this.Response.StatusCode = (int)HttpStatusCode.NotFound;
                return null;
            }
            else
            {
                return View(item);
            }
        }

        [AcceptVerbs(HttpVerbs.Post), System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "form", Justification = "the param is need to disambiguate from the GET method")]
        public ActionResult EditItem(int id, FormCollection form)
        {
            AuctionDataServiceContext ctx = new AuctionDataServiceContext(this.TableAccountInfo);
            AuctionItem item = ctx.AuctionItems.Where<AuctionItem>(i => i.PartitionKey == id.ToString()).Single<AuctionItem>();

            if (!this.TryUpdateModel<AuctionItem>(item))
            {
                return this.EditItem(id);
            }

            string fullSizeImage;
            string thumbnailImage;
            if (CreateImages(out fullSizeImage, out thumbnailImage))
            {
                item.FullSizeImage = fullSizeImage;
                item.Thumbnail = thumbnailImage;
            }

            ctx.UpdateObject(item);
            ctx.SaveChangesWithRetries();

            return RedirectToAction("EditItem", new { id = id });
        }

        /// <summary>
        /// I know this is a GET.  Tough luck for now.
        /// </summary>
        public ActionResult DeleteItem(int id)
        {
            AuctionDataServiceContext ctx = new AuctionDataServiceContext(this.TableAccountInfo);
            AuctionItem item = ctx.AuctionItems.Where<AuctionItem>(i => i.PartitionKey == id.ToString()).Single<AuctionItem>();

            ctx.DeleteObject(item);
            ctx.SaveChangesWithRetries();

            return RedirectToAction("Items", "Home", new { itemNumber = id });
        }

        /// <summary>
        /// I know this is a GET.  Tough luck for now.
        /// </summary>
        public ActionResult UpdateItemThumbnail(int id)
        {
            AuctionDataServiceContext ctx = new AuctionDataServiceContext(this.TableAccountInfo);
            AuctionItem item = ctx.AuctionItems.Where<AuctionItem>(i => i.PartitionKey == id.ToString()).Single<AuctionItem>();

            if (!string.IsNullOrEmpty(item.FullSizeImage))
            {
                item.Thumbnail = Utilities.CreateThumbnail(
                    this.BlobContainer,
                    item.FullSizeImage,
                    350,
                    350,
                    true);

                ctx.UpdateObject(item);
                ctx.SaveChangesWithRetries();
            }

            return RedirectToAction("Details", "Home", new { itemNumber = id });
        }


        public ActionResult CreateCategory()
        {
            ViewData["Title"] = "Create Category";
            return View();
        }

        [AcceptVerbs(HttpVerbs.Post)]
        public ActionResult CreateCategory(string name)
        {
            Category category = new Category()
            {
                Id = SequenceNumber.GetNextSequenceNumber(this.TableAccountInfo, "CategoryNumber"),
                Name = name
            };

            AuctionDataServiceContext ctx = new AuctionDataServiceContext(this.TableAccountInfo);
            ctx.AddObject(AuctionDataServiceContext.CategoriesTableName, category);
            ctx.SaveChangesWithRetries();

            return this.CreateCategory();
        }

        public ActionResult ImportItems()
        {
            AuctionDataServiceContext ctx = new AuctionDataServiceContext(this.TableAccountInfo);

            ViewData["Title"] = "Import Items";
            return View();
        }

        [AcceptVerbs(HttpVerbs.Post)]
        public ActionResult ImportItems(FormCollection form)
        {

            if (this.Request.Files.Count != 1 || this.Request.Files[0].ContentLength == 0)
            {
                this.ViewData.ModelState.AddModelError("itemsFile", "Please enter an items file");
            }

            if (!this.ViewData.ModelState.IsValid)
            {
                return this.ImportItems();
            }

            StringBuilder result = new StringBuilder();

            HttpPostedFileBase file = this.Request.Files[0];
            using (XmlReader reader = XmlReader.Create(file.InputStream))
            {
                AuctionDataServiceContext ctx = new AuctionDataServiceContext(this.TableAccountInfo);
                XDocument document = XDocument.Load(reader);
                foreach (XElement element in document.Descendants("Row"))
                {
                    AuctionItem item = AuctionItemFromElement(element);

                    IEnumerable<AuctionItem> query = ctx.AuctionItems.Where(i => i.Name == HttpUtility.UrlEncode(item.Name)); // Hack around astoria encoding bug
                    if (query.Any())
                    {
                        result.AppendFormat("\"{0}\" not imported because it already exists.\n", item.Name);
                        continue;
                    }

                    try
                    {
                        item.Number = SequenceNumber.GetNextSequenceNumber(this.TableAccountInfo, "ItemNumber");
                        ctx.AddObject(AuctionDataServiceContext.AuctionItemsTableName, item);
                        ctx.SaveChangesWithRetries();
                    }
                    catch (InvalidOperationException)
                    {
                        result.AppendFormat("\"{0}\" not imported because we got an exception.\n", item.Name);
                    }
                }
            }

            if (result.Length == 0)
            {
                return Content("Successfully imported content");
            }

            return Content(result.ToString());
        }

        private AuctionItem AuctionItemFromElement(XElement element)
        {
            AuctionItem item = new AuctionItem()
            {
                Name = element.Element("Title").Value,
                Donor = element.Element("Donor").Value,
                EstimatedValue = Convert.ToInt32(element.Element("Value").Value)
            };

            // Handle fields that may not always be there.
            XElement description = element.Element("Description");
            if (description != null)
            {
                item.Description = description.Value;
            }

            return item;
        }
    }
}
